<!-- uniapp vue3 markdown解析 -->
<template>
<view class="ua__markdown"><rich-text space="nbsp" :nodes="parseNodes(source)" @itemclick="handleItemClick"></rich-text></view>
</template>

<script setup>
import { ref, computed } from 'vue'
import MarkdownIt from 'markdown-it';
	// import MarkdownIt from './lib/markdown-it.min.js'
import hljs from './lib/highlight/uni-highlight.min.js'
import './lib/highlight/atom-one-dark.css'
import parseHtml from './lib/html-parser.js'
	const props = defineProps({
		// 解析内容
	source: String,
	  showLine: { type: [Boolean, String], default: true }
	})
	
	let copyCodeData = []
 const markdown = MarkdownIt({
		 html: true,
	 highlight: function(str, lang) {
		let preCode = ""
		try {
		preCode = hljs.highlightAuto(str).value
		} catch (err) {
		preCode = markdown.utils.escapeHtml(str);
			}
		const lines = preCode.split(/\n/).slice(0, -1)
		// 添加自定义行号
	let html = lines.map((item, index) => {
	    return `<li style="margin:0;padding:0;line-height:1;min-height:0;">${item}</li>`;
	}).join('');
	
	html = `<ol style="margin:0;padding:0;${!props.showLine ? 'list-style:none;' : ''}">${html}</ol>`;
	copyCodeData.push(str)
		let htmlCode = `<div class="markdown-wrap">`
				// #ifndef MP-WEIXIN
			htmlCode += `<div style="color: #aaa;text-align: right;font-size: 12px;padding:8px;">`
					htmlCode += `${lang}<a class="copy-btn" code-data-index="${copyCodeData.length - 1}" style="margin-left: 8px;">复制代码</a>`
					htmlCode += `</div>`
				// #endif
		htmlCode += `<pre class="hljs" style="padding:10px 8px 0;margin-bottom:5px;overflow: auto;display: block;border-radius: 5px;"><code>${html}</code></pre>`;
			htmlCode += '</div>'
	return htmlCode
	}
	})
  // 新增：为标题标签添加自定义 class（h1-h6）
  markdown.renderer.rules.heading_open = function(tokens, idx, options, env, self) {
    const tag = tokens[idx].tag; // 获取标签类型（如 'h1', 'h2', 'h3'）
    tokens[idx].attrPush(['class', `markdown-${tag}`]); // 添加 class="markdown-h3"（以 h3 为例）
    return self.renderToken(tokens, idx, options);
  };
  
  // 可选：为段落添加 class（如需要修改段落字体）
  markdown.renderer.rules.paragraph_open = function(tokens, idx, options, env, self) {
    tokens[idx].attrPush(['class', 'markdown-p']); // 添加 class="markdown-p"
    return self.renderToken(tokens, idx, options);
  };
  // 新增：为 li 标签添加自定义 class
  markdown.renderer.rules.list_item_open = function(tokens, idx, options, env, self) {
    tokens[idx].attrPush(['class', 'markdown-li']); // 添加 class="markdown-li"
    return self.renderToken(tokens, idx, options);
  };
 // 替换原来的list_open规则
 markdown.renderer.rules.ordered_list_open = function(tokens, idx, options, env, self) {
   tokens[idx].attrPush(['class', 'markdown-ol']);
   return self.renderToken(tokens, idx, options);
 };
 
 markdown.renderer.rules.bullet_list_open = function(tokens, idx, options, env, self) {
   tokens[idx].attrPush(['class', 'markdown-ul']);
   return self.renderToken(tokens, idx, options);
 };
const parseNodes = (value) => {
	 if(!value) return
		 // 解析<br />到\n
	  value = value.replace(/<br>|<br\/>|<br \/>/g, "\n")
	value = value.replace(/&nbsp;/g, " ")
		 let htmlString = ''
	if (value.split("```").length % 2) {
		let mdtext = value
		if(mdtext[mdtext.length-1] != '\n'){
		mdtext += '\n'
			}
	  htmlString = markdown.render(mdtext)
		} else {
		htmlString = markdown.render(value)
		}
		// 解决小程序表格边框型失效问题
htmlString = htmlString.replace(/<table/g, `<table class="table"`)
		htmlString = htmlString.replace(/<tr/g, `<tr class="tr"`)
	htmlString = htmlString.replace(/<th>/g, `<th class="th">`)
htmlString = htmlString.replace(/<td/g, `<td class="td"`)
	htmlString = htmlString.replace(/<hr>|<hr\/>|<hr \/>/g, `<hr class="hr">`)
		// #ifndef APP-NVUE
		return htmlString
		// #endif
		
		// 将htmlString转成htmlArray，反之使用rich-text解析
		// #ifdef APP-NVUE
	return parseHtml(htmlString)
		// #endif
  
	}
	
// 复制代码
const handleItemClick = (e) => {
	let {attrs} = e.detail.node
let {"code-data-index":codeDataIndex,"class":className} = attrs
	if(className == 'copy-btn'){
	uni.setClipboardData({
		data: copyCodeData[codeDataIndex],showToast: false,
		success() {
			uni.showToast({
				title: '复制成功',icon: 'none'
				});
				}
			})
		}
	}
</script>

<style lang="scss" scoped>
.ua__markdown {
	  font-size: 28rpx;line-height: 1.1; word-break: break-all;
	  h1,h2,h3,h4,h5,h6 {
	       font-family: inherit;font-weight:bold;line-height: 1.1;color: inherit;
	    }
	  h1,h2,h3 {margin-top: 30rpx;margin-bottom: 30rpx}
	   h4,h5,h6 {margin-top: 10px;margin-bottom: 10px}
	    .h1,h1 {font-size: 30rpx
	    }
	   .h2,h2 {font-size: 28rpx
	    }
	  .h3,h3 {font-size: 32rpx
	    }
	  .h4,h4 {font-size: 18px
	    }
	    .h5,h5 {font-size: 14px
	    }
	  .h6,h6 {font-size: 12px
	    }
	 a {
	     background-color: transparent;color: #2196f3;
	        text-decoration: none;
	    }
	 hr, ::v-deep .hr {
	   margin:0rpx; border: 0; border-top: 1px solid #e5e5e5;
	    }
	    img { max-width: 35%;
	    }
	  p {margin: 0}
	  em {
	      font-style: italic; font-weight: inherit;
	    }
	 ol,ul {
	        margin-top: 0; margin-bottom: 0;padding-left: 20rpx;
	    }
	  ol ol,ol ul,ul ol,ul ul {margin-bottom: 0;
	    }
	ol ol, ul ol {list-style-type: none;margin-bottom: 0;
  
	    }
	   ol ol ol, ul ul ol {list-style-type: none;margin-bottom: 0;
	    }
	 dl {
	    margin-top: 0;margin-bottom: 20px;
	    }
	  dt {font-weight: 600;
	    }
	dt, dd {line-height: 1.4;
	    }
	 .task-list-item { list-style-type: none;
	    }
	 .task-list-item input {
	        margin: 0 .2em .25em -1.6em;vertical-align: middle;
	    }
	    pre {
	       position: relative; z-index: 11;
	    }
	    code,kbd,pre,samp { font-family: Menlo,Monaco,Consolas,"Courier New",monospace;}
	    code:not(.hljs) {
	    padding: 2px 4px;font-size: 90%;color: #c7254e;background-color: #ffe7ee;border-radius: 4px;
	    }
code:empty {display: none;
		}
	  pre code.hljs {
	      color: var(--vg__text-1); border-radius: 16px; background: var(--vg__bg-1);font-size: 12px;
	    }
.markdown-wrap {
			font-size: 12px;margin-bottom: 10px;
		}
	    pre.code-block-wrapper {background: #2b2b2b;color: #f8f8f2;border-radius: 4px;overflow-x: auto;
	        padding: 1em;
	        position: relative;
	    }
	   pre.code-block-wrapper code {
	        padding: auto;
	        font-size: inherit;
	        color: inherit;
	        background-color: inherit;
	        border-radius: 0;
	    }
	    .code-block-header__copy {
	        font-size: 16px;margin-left: 5px;
	    }
	 abbr[data-original-title],abbr[title] {
	        cursor: help;border-bottom: 1px dotted #777;
	    }
	    blockquote {
	     padding: 0;margin: 0;font-size: 17.5px;
	        border-left: 5px solid #e5e5e5;
	    }
	 blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child {
	        margin-bottom: 0
	    }
	blockquote .small,blockquote footer,blockquote small {
	      display: block;font-size: 80%;line-height: 1.42857143;color: #777
	    }
	  blockquote .small:before,blockquote footer:before,blockquote small:before {
	        content: '\2014 \00A0'
	    }
	    .blockquote-reverse,blockquote.pull-right {
	        padding-right: 15px; padding-left: 0;
	     text-align: right;border-right: 5px solid #eee;border-left: 0
	    }
	  .blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before {
	        content: ''
	    }
	  .blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after {
	        content: '\00A0 \2014'
	    }
	   .footnotes {
	      -moz-column-count: 2;
	        -webkit-column-count: 2;
	     column-count: 2
	    }
	    .footnotes-list {padding-left: 2em}
	   table, ::v-deep .table {
	    border-spacing: 0;border-collapse: collapse; width: 100%;max-width: 65em; overflow: auto;margin-top: 0;
	        margin-bottom: 16px;
	    }
	  table tr, ::v-deep .table .tr {
	   border-top: 1px solid #e5e5e5;
	    }
	    table th, table td, ::v-deep .table .th, ::v-deep .table .td {
	  padding: 6px 13px;border: 1px solid #e5e5e5;
	    }
	    table th, ::v-deep .table .th {
	      font-weight: 600;background-color: #eee;
	    }
	    .hljs[class*=language-]:before {
	    position: absolute; z-index: 3;top: .8em; right: 1em; font-size: .8em; color: #999;
	    }
	    .hljs[class~=language-js]:before {
     content: "js"
    }
    .hljs[class~=language-ts]:before {
        content: "ts"
    }
    .hljs[class~=language-html]:before {
        content: "html"
}
.hljs[class~=language-md]:before {
    content: "md"
}
.hljs[class~=language-vue]:before {
    content: "vue"
}
.hljs[class~=language-css]:before {
    content: "css"
}
    .hljs[class~=language-sass]:before {
        content: "sass"
    }
    .hljs[class~=language-scss]:before {
        content: "scss"
    }
.hljs[class~=language-less]:before {
    content: "less"
}
    .hljs[class~=language-stylus]:before {
        content: "stylus"
    }
    .hljs[class~=language-go]:before {
        content: "go"
    }
    .hljs[class~=language-java]:before {
    content: "java"
}
.hljs[class~=language-c]:before {
    content: "c"
}
.hljs[class~=language-sh]:before {
    content: "sh"
}
    .hljs[class~=language-yaml]:before {
        content: "yaml"
}
    .hljs[class~=language-py]:before {
        content: "py"
}
.hljs[class~=language-docker]:before {
    content: "docker"
}
.hljs[class~=language-dockerfile]:before {
    content: "dockerfile"
	}
	.hljs[class~=language-makefile]:before {
	    content: "makefile"
}
.hljs[class~=language-javascript]:before {
    content: "js"
}
.hljs[class~=language-typescript]:before {
        content: "ts"
    }
    .hljs[class~=language-markup]:before {
        content: "html"
}
.hljs[class~=language-markdown]:before {
    content: "md"
}
    .hljs[class~=language-json]:before {
        content: "json"
    }
    .hljs[class~=language-ruby]:before {
        content: "rb"
    }
	    .hljs[class~=language-python]:before {
	        content: "py"
	    }
    .hljs[class~=language-bash]:before {
        content: "sh"
    }
    .hljs[class~=language-php]:before {
        content: "php"
    }
    // 修改 h3 字体大小（通过 class 定位）
    ::v-deep .markdown-h3 {
      font-size: 32rpx;  // 自定义字体大小
      line-height: 1.2; // 可选：调整行高
    }
    ::v-deep .markdown-h1 {
      font-size: 36rpx;  // 自定义字体大小
      line-height: 1.2; // 可选：调整行高
    }
    ::v-deep .markdown-h2 {
      font-size: 34rpx;  // 自定义字体大小
      line-height: 1.2; // 可选：调整行高
    }
    ::v-deep .markdown-ul {
      padding: 0  !important;  // 调整 li 的缩进距离（原 20rpx）
      margin:  0 0 0 30rpx !important;      // 调整列表整体与其他元素的上下间距
      line-height: 1 !important;
      list-style: none !important; /* 移除项目符号 */
      
    }
    ::v-deep .markdown-ol {
      padding: 0rpx !important;  // 调整 li 的缩进距离（原 20rpx）
      margin: 0 0 0 30rpx!important;      // 调整列表整体与其他元素的上下间距
      line-height:1 !important;
      list-style: none !important; /* 移除项目符号 */
    }
    ::v-deep .markdown-p {
      margin: 0 !important;  // 调整上下间距（可根据需求修改数值）
      padding: 0; // 可选：调整内边距
    }
	}
  .ua__markdown ::v-deep .markdown-li {  /* 增加父容器限定，增强选择器特异性 */
    margin: 0 !important;
    padding: 0rpx !important;
    line-height: 1;
    min-height: 0 !important;
  }
</style>
